package com.maimao.order.job;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.api.R;
import com.google.common.collect.Lists;
import com.maimao.model.order.Order;
import com.maimao.model.order.OrderProcessing;
import com.maimao.model.order.enums.OrderProcessingType;
import com.maimao.model.order.enums.OrderStatus;
import com.maimao.order.serivce.OrderProcessingService;
import com.maimao.order.serivce.OrderService;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 处理取消订单失败的订单
 * @author MaoLin Wang
 * @date 2021/4/6 4:26 下午
 */
@Component
@Slf4j
public class CancelOrderJobHandler {

    @Autowired
    private OrderProcessingService orderProcessingService;

    @Autowired
    private OrderService orderService;

    private static final Integer MAX_RETRY_COUNT = 1;

    @XxlJob("cancelOrderJobHandler")
    public ReturnT cancelOrderJobHandler() {
        List<OrderProcessing> orderProcessingList = orderProcessingService.undoList();
        if (ObjectUtil.isNotEmpty(orderProcessingList)) {
            List<Long> orderIds = orderProcessingList.stream().map(OrderProcessing::getId).collect(Collectors.toList());
            XxlJobHelper.log("开始处理待取消订单，订单id列表:{}", orderIds);

            List<OrderProcessing> removeList = Lists.newArrayListWithCapacity(orderIds.size());
            List<OrderProcessing> failList = Lists.newArrayListWithCapacity(orderIds.size());

            while (orderProcessingList.size() > 0) {
                doCancel(orderProcessingList.iterator(), removeList, failList);
            }
            if (removeList.size() > 0) {
                List<Long> ids = removeList.stream().map(OrderProcessing::getId).collect(Collectors.toList());
                XxlJobHelper.log("待删除的记录为:{}", StrUtil.join(",", ids));
                orderProcessingService.deleteBatch(ids);
            }
            if (failList.size() > 0) {
                List<Long> ids = failList.stream().map(OrderProcessing::getId).collect(Collectors.toList());
                XxlJobHelper.log("取消状态失败的记录为:{}", StrUtil.join(",", ids));
                orderProcessingService.updateBatch(failList);
            }

        }
        return ReturnT.SUCCESS;
    }


    private void doCancel(Iterator<OrderProcessing> iterator, List<OrderProcessing> removeEntity, List<OrderProcessing> failList) {
        while (iterator.hasNext()) {
            OrderProcessing orderProcessing = null;
            try {
                orderProcessing = iterator.next();
                //1、校验订单是否已经支付，查询该订单的支付状态
                Order order = orderService.queryOrder(orderProcessing.getId());
                //2、如果未支付就把订单取消，修改订单状态
                //如果事务回滚，则订单未创建成功，但是发送了消息，因此这里order == null ，直接确认即可
                if (order != null) {
                    orderService.cancelOrder(orderProcessing.getId(), order.getUserId());
                    orderProcessing.setStatus(OrderProcessingType.DONE.getStatus());
                    log.info("修改订单{}状态为取消---->", orderProcessing.getId());
                    removeEntity.add(orderProcessing);
                    iterator.remove();
                } else {
                    removeEntity.add(orderProcessing);
                    iterator.remove();
                }
            } catch (Exception e) {
                if (orderProcessing == null) {
                    continue;
                }
                Integer retryCnt = orderProcessing.getRetryCnt();
                if (retryCnt == null) {
                    retryCnt = 0;
                }

                //因为Rabbit消息过期那里已经重试了3次，这里只重试一次
                if (orderProcessing.getRetryCnt() >= MAX_RETRY_COUNT) {
                    orderProcessing.setStatus(OrderProcessingType.FAIL.getStatus());
                    failList.add(orderProcessing);
                    iterator.remove();
                } else {
                    orderProcessing.setRetryCnt(++retryCnt);
                    continue;
                }
            }
        }
    }
}
